/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.ContextFree;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
import main.Concurrent.Iteration.IterationHelper;
import main.Concurrent.Iteration.IterationOperation;
import main.Trie.AbstractTrie;

/**
 *
 * @author Isaac Osesina
 */
public class RegexCompare<K> extends HashMap<K, HashMap<K, Boolean>> implements Serializable, Cloneable {

    Map<K, Pattern> patterns;

    public RegexCompare() {
        super();
        this.patterns = new HashMap<K, Pattern>();
    }

    
    public Pattern addRegex(K entityName, Pattern pattern) {
        return patterns.put(entityName, pattern);
    }
    
    public void setRegex(Map<K, Pattern> patterns) {
        this.patterns = patterns;
    }

    public void generatePatternComparisons() {
        Set<Entry<K, Pattern>> entrySet = patterns.entrySet();
        int length = entrySet.size();
        
        PatternComparisonGenerationOperation<K> op =
                new PatternComparisonGenerationOperation(patterns);
        
        this.putAll(IterationHelper.runIteration(
                "PatternComparisonIteration", 
                entrySet, op, 
                new HashMap<K, HashMap<K, Boolean>>(), 
                length));
        
    }

    public boolean isRegexOverlap(K regexType1, K regexType2) {
        HashMap<K, Boolean> regType1Overlaps = this.get(regexType1);
        if (regType1Overlaps == null || !regType1Overlaps.containsKey(regexType2))
            return false;
        return regType1Overlaps.get(regexType2);
    }

    public boolean isRegexOverlap(K regexType) {
        boolean overlap = false;
        if(regexType == null)
            return overlap;
        HashMap<K, Boolean> comparisonMap = this.get(regexType);
        Iterator<K> iterator = comparisonMap.keySet().iterator();
        while( iterator.hasNext() && !overlap ) {
            Boolean pairWiseOverlap = comparisonMap.get(iterator.next());
            if(pairWiseOverlap != null) {
                overlap = pairWiseOverlap;
            }
        }
        return overlap;
    }

    private static class PatternComparisonGenerationOperation<K> implements 
    IterationOperation<
        Entry<K, Pattern>,
        Entry<K, HashMap<K, Boolean>>,
        HashMap<K, HashMap<K, Boolean>>
        > {
        
        private Map<K, Pattern> patterns;
        
        public PatternComparisonGenerationOperation(Map<K, Pattern> patterns) {
            this.patterns = patterns;
        }

        @Override
        public Entry<K, HashMap<K, Boolean>>
            compute(int index, Entry<K, Pattern> entry) {
            
            Set<K> keySet = patterns.keySet();
            Pattern pattern1 = entry.getValue();
            if(pattern1 ==null)
                return null;
            RegexToAutomaton r2A = new RegexToAutomaton(pattern1.pattern());
            HashMap<K, Boolean> comparisonMap = new HashMap<K, Boolean>();
            for(K regexType:keySet) {
                if(!regexType.equals(entry.getKey())) {
                    Pattern pattern2 = patterns.get(regexType);
//                        if(regexType.compareTo("DecedentAge")==0)
//                        {
//                            System.out.println(pattern2.pattern());
//                        }
                    if(pattern2 != null) {
                        comparisonMap.put(regexType, r2A.isOverlap(pattern2.pattern()));
                    }
                }
            }
            
            return new AbstractTrie.Entry<K, HashMap<K, Boolean>>(entry.getKey(), comparisonMap);
        }

        @Override
        public HashMap<K, HashMap<K, Boolean>> aggregate(
                HashMap<K, HashMap<K, Boolean>> current,
                int index,
                java.util.Map.Entry<K, HashMap<K, Boolean>> result) {
            if(result == null) {
                return current;
            }
            
            current.put(result.getKey(), result.getValue());
            return current;
        }
        
    }
}
